#ifndef DXOBJMESHLOADER_H_
#define DXOBJMESHLOADER_H_

#include "MeshLoader.h"
#pragma warning(disable: 4995)
#include <fstream>
#pragma warning(default: 4995)
#pragma once


namespace Loader
{

    // Material properties per mesh subset
    struct Material
    {
        WCHAR   strName[MAX_PATH];

        D3DXVECTOR4 vAmbient;
        D3DXVECTOR4 vDiffuse;
        D3DXVECTOR4 vSpecular;

        int nShininess;
        float fAlpha;

        bool bSpecular;

        WCHAR   strTexture[MAX_PATH];
        ID3D10ShaderResourceView* pTextureRV10;
        ID3D10EffectTechnique*  pTechnique;
    };

    // Vertex format
    struct VERTEX
    {
        D3DXVECTOR3 position;
        D3DXVECTOR3 normal;
        D3DXVECTOR2 texcoord;
    };


    // Used for a hashtable vertex cache when creating the mesh from a .obj file
    struct CacheEntry
    {
        UINT index;
        CacheEntry* pNext;
    };


    class DXObjMeshLoader : public MeshLoader
    {
    public:
        DXObjMeshLoader();
        ~DXObjMeshLoader();

        HRESULT Create( ID3D10Device* pd3dDevice, const WCHAR* strFilename );

        void    Destroy();

        UINT    GetNumMaterials() const
        {
            return m_Materials.GetSize();
        }
        Material* GetMaterial( UINT iMaterial )
        {
            return m_Materials.GetAt( iMaterial );
        }

        UINT GetNumSubsets() const
        {
            return m_NumAttribTableEntries;
        }
        WCHAR* GetMediaDirectory()
        {
            return m_strMediaDir;
        }
        void DrawSubset(ID3D10Device* pd3dDevice, UINT iSubset)
        {
            m_pMesh->DrawSubset(iSubset);
        }
        D3DXVECTOR4 GetSubsetMaterialAmbient(UINT iSubset)
        {
            return m_Materials.GetAt( m_pAttribTable[iSubset].AttribId )->vAmbient;
        }
        D3DXVECTOR4 GetSubsetMaterialDiffuse(UINT iSubset)
        {
            return m_Materials.GetAt( m_pAttribTable[iSubset].AttribId )->vDiffuse;
        }
        D3DXVECTOR4 GetSubsetMaterialSpecular(UINT iSubset)
        {
            return m_Materials.GetAt( m_pAttribTable[iSubset].AttribId )->vSpecular;
        }
        float GetSubsetMaterialAlpha(UINT iSubset)
        {
            return m_Materials.GetAt( m_pAttribTable[iSubset].AttribId )->fAlpha;
        }
        int GetSubsetMaterialSpecularPower(UINT iSubset)
        {
            return m_Materials.GetAt( m_pAttribTable[iSubset].AttribId )->nShininess;
        }
        ID3D10ShaderResourceView* GetSubsetMaterialDiffuseTxRV(UINT iSubset)
        {
            return m_Materials.GetAt( m_pAttribTable[iSubset].AttribId )->pTextureRV10;
        }
        ID3D10EffectTechnique* GetSubsetMaterialTech(UINT iSubset)
        {
            return m_Materials.GetAt( m_pAttribTable[iSubset].AttribId )->pTechnique;
        }
        WCHAR* GetSubsetMaterialName(UINT iSubset)
        {
            return m_Materials.GetAt( m_pAttribTable[iSubset].AttribId )->strName;
        }
        void SetMaterialTech(ID3D10Effect* g_pEffect10)
        {
            for ( UINT i = 0; i < m_Materials.GetSize(); ++i )
            {
                Loader::Material* pMaterial = GetMaterial( i );

                const char* strTechnique = "";

                if( pMaterial->pTextureRV10 && pMaterial->bSpecular )
                    strTechnique = "TexturedSpecular";
                else if( pMaterial->pTextureRV10 && !pMaterial->bSpecular )
                    strTechnique = "TexturedNoSpecular";
                else if( !pMaterial->pTextureRV10 && pMaterial->bSpecular )
                    strTechnique = "Specular";
                else if( !pMaterial->pTextureRV10 && !pMaterial->bSpecular )
                    strTechnique = "NoSpecular";

                pMaterial->pTechnique = g_pEffect10->GetTechniqueByName( strTechnique );
            }
        }
        void SetIAVertexIndexBuffer(ID3D10Device* pd3dDevice)
        {

        }
        float GetAutoViewDistance()
        {
            //TODO:
            return 2;
        }



    private:

        HRESULT LoadGeometryFromOBJ( const WCHAR* strFilename );
        HRESULT LoadMaterialsFromMTL( const WCHAR* strFileName );
        void    InitMaterial( Material* pMaterial );

        DWORD   AddVertex( UINT hash, VERTEX* pVertex );
        void    DeleteCache();

        ID3D10Device* m_pd3dDevice;    // Direct3D Device object associated with this mesh
        ID3DX10Mesh* m_pMesh;         // Encapsulated D3DX Mesh

        CGrowableArray <CacheEntry*> m_VertexCache;   // Hashtable cache for locating duplicate vertices
        CGrowableArray <VERTEX> m_Vertices;      // Filled and copied to the vertex buffer
        CGrowableArray <DWORD> m_Indices;       // Filled and copied to the index buffer
        CGrowableArray <DWORD> m_Attributes;    // Filled and copied to the attribute buffer
        CGrowableArray <Material*> m_Materials;     // Holds material properties per subset

        UINT        m_NumAttribTableEntries;
        D3DX10_ATTRIBUTE_RANGE *m_pAttribTable;

        WCHAR   m_strMediaDir[ MAX_PATH ];               // Directory where the mesh was found
    };
}

#endif DXOBJMESHLOADER_H_
